package biz

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"regexp"
	"time"

	"github.com/go-kratos/kratos/v2/log"
)

// User 用户信息
type User struct {
	ID        int64     `gorm:"primaryKey;autoIncrement;comment:用户ID"`             // 用户ID
	Username  string    `gorm:"type:varchar(50);uniqueIndex;not null;comment:用户名"` // 用户名
	Password  string    `gorm:"type:varchar(255);not null;comment:密码"`             // 密码（加密后）
	Nickname  string    `gorm:"type:varchar(50);comment:昵称"`                       // 昵称
	Email     string    `gorm:"type:varchar(100);comment:邮箱"`                      // 邮箱
	Phone     string    `gorm:"type:varchar(20);comment:手机号"`                      // 手机号
	Avatar    string    `gorm:"type:varchar(255);comment:头像"`                      // 头像
	Points    int64     `gorm:"default:0;comment:积分"`                              // 积分
	Status    int8      `gorm:"default:1;comment:状态 1:正常 0:禁用"`                    // 状态 1:正常 0:禁用
	CreatedAt time.Time `gorm:"comment:创建时间"`                                      // 创建时间
	UpdatedAt time.Time `gorm:"comment:更新时间"`                                      // 更新时间
}

// PointsRecord 积分记录
type PointsRecord struct {
	ID          int64     `gorm:"primaryKey;autoIncrement;comment:记录ID"`  // 记录ID
	UserID      int64     `gorm:"not null;index;comment:用户ID"`            // 用户ID
	Points      int64     `gorm:"not null;comment:积分变动数量"`                // 积分变动数量
	Type        string    `gorm:"type:varchar(20);not null;comment:积分类型"` // 积分类型
	Description string    `gorm:"type:varchar(255);comment:描述"`           // 描述
	OrderID     int64     `gorm:"default:0;comment:关联订单ID"`               // 关联订单ID
	CreatedAt   time.Time `gorm:"comment:创建时间"`                           // 创建时间
}

// PointsRule 积分规则
type PointsRule struct {
	ID          int64   `gorm:"primaryKey;autoIncrement;comment:规则ID"`    // 规则ID
	Type        string  `gorm:"type:varchar(20);not null;comment:规则类型"`   // 规则类型
	Name        string  `gorm:"type:varchar(50);not null;comment:规则名称"`   // 规则名称
	Description string  `gorm:"type:varchar(255);comment:规则描述"`           // 规则描述
	Rate        float64 `gorm:"type:decimal(10,2);not null;comment:积分比例"` // 积分比例
	MinAmount   int64   `gorm:"default:0;comment:最小金额"`                   // 最小金额
	MaxPoints   int64   `gorm:"default:0;comment:单次最大积分"`                 // 单次最大积分
	Enabled     bool    `gorm:"default:true;comment:是否启用"`                // 是否启用
}

// UserRepo 用户数据访问接口
type UserRepo interface {
	Create(ctx context.Context, user *User) error
	GetByID(ctx context.Context, id int64) (*User, error)
	GetByUsername(ctx context.Context, username string) (*User, error)
	GetByEmail(ctx context.Context, email string) (*User, error)
	GetByPhone(ctx context.Context, phone string) (*User, error)
	Update(ctx context.Context, user *User) error
	UpdatePoints(ctx context.Context, userID int64, points int64) error
}

// PointsRepo 积分数据访问接口
type PointsRepo interface {
	AddPoints(ctx context.Context, userID int64, points int64, pointsType string, description string, orderID int64) error
	GetUserPoints(ctx context.Context, userID int64) (int64, error)
	GetPointsHistory(ctx context.Context, userID int64, page, pageSize int) ([]*PointsRecord, int, error)
	GetPointsRule(ctx context.Context, ruleType string) (*PointsRule, error)
	GetPointsRules(ctx context.Context) ([]*PointsRule, error)
	InitDefaultRules(ctx context.Context) error
}

// UserUsecase 用户业务逻辑
type UserUsecase struct {
	repo UserRepo
	log  *log.Helper
}

// NewUserUsecase 创建用户业务逻辑实例
func NewUserUsecase(repo UserRepo, logger log.Logger) *UserUsecase {
	return &UserUsecase{
		repo: repo,
		log:  log.NewHelper(logger),
	}
}

// Register 用户注册
func (uc *UserUsecase) Register(ctx context.Context, username, password, email, phone, nickname string) (*User, error) {
	// 参数验证
	if err := uc.validateRegisterParams(username, password, email, phone); err != nil {
		return nil, err
	}

	// 检查用户名是否已存在
	existingUser, err := uc.repo.GetByUsername(ctx, username)
	if err != nil {
		uc.log.Errorf("查询用户名失败: %v", err)
		return nil, err
	}
	if existingUser != nil {
		return nil, ErrUserAlreadyExists
	}

	// 检查邮箱是否已存在
	if email != "" {
		existingUser, err = uc.repo.GetByEmail(ctx, email)
		if err != nil {
			uc.log.Errorf("查询邮箱失败: %v", err)
			return nil, err
		}
		if existingUser != nil {
			return nil, ErrEmailAlreadyExists
		}
	}

	// 检查手机号是否已存在
	if phone != "" {
		existingUser, err = uc.repo.GetByPhone(ctx, phone)
		if err != nil {
			uc.log.Errorf("查询手机号失败: %v", err)
			return nil, err
		}
		if existingUser != nil {
			return nil, ErrPhoneAlreadyExists
		}
	}

	// 密码加密
	hashedPassword, err := uc.hashPassword(password)
	if err != nil {
		uc.log.Errorf("密码加密失败: %v", err)
		return nil, ErrInternalServer
	}

	// 创建新用户
	user := &User{
		Username:  username,
		Password:  hashedPassword,
		Email:     email,
		Phone:     phone,
		Nickname:  nickname,
		Points:    0,
		Status:    1,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	err = uc.repo.Create(ctx, user)
	if err != nil {
		uc.log.Errorf("创建用户失败: %v", err)
		return nil, err
	}

	uc.log.Infof("用户注册成功: %s", username)
	return user, nil
}

// Login 用户登录
func (uc *UserUsecase) Login(ctx context.Context, username, password string) (*User, error) {
	// 参数验证
	if username == "" || password == "" {
		return nil, ErrInvalidUsername
	}

	user, err := uc.repo.GetByUsername(ctx, username)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return nil, ErrUserNotExists
	}

	if user == nil {
		return nil, ErrUserNotExists
	}

	// 验证密码
	if !uc.verifyPassword(user.Password, password) {
		uc.log.Warnf("用户密码错误: %s", username)
		return nil, ErrInvalidPassword
	}

	if user.Status != 1 {
		uc.log.Warnf("用户已被禁用: %s", username)
		return nil, ErrUserDisabled
	}

	// 更新最后登录时间
	user.UpdatedAt = time.Now()
	if err := uc.repo.Update(ctx, user); err != nil {
		uc.log.Errorf("更新用户登录时间失败: %v", err)
		// 不影响登录流程
	}

	uc.log.Infof("用户登录成功: %s", username)
	return user, nil
}

// GetUserInfo 获取用户信息
func (uc *UserUsecase) GetUserInfo(ctx context.Context, userID int64) (*User, error) {
	return uc.repo.GetByID(ctx, userID)
}

// UpdateUserInfo 更新用户信息
func (uc *UserUsecase) UpdateUserInfo(ctx context.Context, userID int64, nickname, email, phone, avatar string) error {
	// 参数验证
	if userID <= 0 {
		return ErrUserNotExists
	}

	// 验证邮箱格式
	if email != "" && !uc.isValidEmail(email) {
		return ErrInvalidEmail
	}

	// 验证手机号格式
	if phone != "" && !uc.isValidPhone(phone) {
		return ErrInvalidPhone
	}

	user, err := uc.repo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return err
	}

	if user == nil {
		return ErrUserNotExists
	}

	// 检查邮箱是否被其他用户使用
	if email != "" && email != user.Email {
		existingUser, err := uc.repo.GetByEmail(ctx, email)
		if err != nil {
			uc.log.Errorf("查询邮箱失败: %v", err)
			return err
		}
		if existingUser != nil && existingUser.ID != userID {
			return ErrEmailAlreadyExists
		}
	}

	// 检查手机号是否被其他用户使用
	if phone != "" && phone != user.Phone {
		existingUser, err := uc.repo.GetByPhone(ctx, phone)
		if err != nil {
			uc.log.Errorf("查询手机号失败: %v", err)
			return err
		}
		if existingUser != nil && existingUser.ID != userID {
			return ErrPhoneAlreadyExists
		}
	}

	// 更新用户信息
	user.Nickname = nickname
	user.Email = email
	user.Phone = phone
	user.Avatar = avatar
	user.UpdatedAt = time.Now()

	err = uc.repo.Update(ctx, user)
	if err != nil {
		uc.log.Errorf("更新用户信息失败: %v", err)
		return err
	}

	uc.log.Infof("用户信息更新成功: %d", userID)
	return nil
}

// GetUserPoints 获取用户积分
func (uc *UserUsecase) GetUserPoints(ctx context.Context, userID int64) (int64, error) {
	if userID <= 0 {
		return 0, ErrUserNotExists
	}

	user, err := uc.repo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return 0, err
	}

	if user == nil {
		return 0, ErrUserNotExists
	}

	return user.Points, nil
}

// ChangePassword 修改密码
func (uc *UserUsecase) ChangePassword(ctx context.Context, userID int64, oldPassword, newPassword string) error {
	if userID <= 0 {
		return ErrUserNotExists
	}

	if len(newPassword) < 6 {
		return ErrPasswordTooShort
	}

	user, err := uc.repo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return err
	}

	if user == nil {
		return ErrUserNotExists
	}

	// 验证旧密码
	if !uc.verifyPassword(user.Password, oldPassword) {
		return ErrInvalidPassword
	}

	// 加密新密码
	hashedPassword, err := uc.hashPassword(newPassword)
	if err != nil {
		uc.log.Errorf("密码加密失败: %v", err)
		return ErrInternalServer
	}

	// 更新密码
	user.Password = hashedPassword
	user.UpdatedAt = time.Now()

	err = uc.repo.Update(ctx, user)
	if err != nil {
		uc.log.Errorf("更新密码失败: %v", err)
		return err
	}

	uc.log.Infof("用户密码修改成功: %d", userID)
	return nil
}

// DisableUser 禁用用户
func (uc *UserUsecase) DisableUser(ctx context.Context, userID int64) error {
	if userID <= 0 {
		return ErrUserNotExists
	}

	user, err := uc.repo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return err
	}

	if user == nil {
		return ErrUserNotExists
	}

	user.Status = 0
	user.UpdatedAt = time.Now()

	err = uc.repo.Update(ctx, user)
	if err != nil {
		uc.log.Errorf("禁用用户失败: %v", err)
		return err
	}

	uc.log.Infof("用户已被禁用: %d", userID)
	return nil
}

// EnableUser 启用用户
func (uc *UserUsecase) EnableUser(ctx context.Context, userID int64) error {
	if userID <= 0 {
		return ErrUserNotExists
	}

	user, err := uc.repo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return err
	}

	if user == nil {
		return ErrUserNotExists
	}

	user.Status = 1
	user.UpdatedAt = time.Now()

	err = uc.repo.Update(ctx, user)
	if err != nil {
		uc.log.Errorf("启用用户失败: %v", err)
		return err
	}

	uc.log.Infof("用户已被启用: %d", userID)
	return nil
}

// 错误定义
var (
	ErrUserAlreadyExists  = &BusinessError{Code: 4001, Message: "用户已存在"}
	ErrUserNotExists      = &BusinessError{Code: 4002, Message: "用户不存在"}
	ErrInvalidPassword    = &BusinessError{Code: 4003, Message: "密码错误"}
	ErrUserDisabled       = &BusinessError{Code: 4004, Message: "用户已被禁用"}
	ErrEmailAlreadyExists = &BusinessError{Code: 4005, Message: "邮箱已存在"}
	ErrPhoneAlreadyExists = &BusinessError{Code: 4006, Message: "手机号已存在"}
	ErrInvalidUsername    = &BusinessError{Code: 4007, Message: "用户名格式不正确"}
	ErrInvalidEmail       = &BusinessError{Code: 4008, Message: "邮箱格式不正确"}
	ErrInvalidPhone       = &BusinessError{Code: 4009, Message: "手机号格式不正确"}
	ErrPasswordTooShort   = &BusinessError{Code: 4010, Message: "密码长度不能少于6位"}
	ErrInternalServer     = &BusinessError{Code: 5000, Message: "服务器内部错误"}
)

// BusinessError 业务错误
type BusinessError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func (e *BusinessError) Error() string {
	return e.Message
}

// validateRegisterParams 验证注册参数
func (uc *UserUsecase) validateRegisterParams(username, password, email, phone string) error {
	// 验证用户名
	if len(username) < 3 || len(username) > 20 {
		return ErrInvalidUsername
	}

	// 验证密码
	if len(password) < 6 {
		return ErrPasswordTooShort
	}

	// 验证邮箱格式
	if email != "" {
		if !uc.isValidEmail(email) {
			return ErrInvalidEmail
		}
	}

	// 验证手机号格式
	if phone != "" {
		if !uc.isValidPhone(phone) {
			return ErrInvalidPhone
		}
	}

	return nil
}

// isValidEmail 验证邮箱格式
func (uc *UserUsecase) isValidEmail(email string) bool {
	// 简单的邮箱格式验证
	emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	return emailRegex.MatchString(email)
}

// isValidPhone 验证手机号格式
func (uc *UserUsecase) isValidPhone(phone string) bool {
	// 简单的手机号格式验证（中国大陆）
	phoneRegex := regexp.MustCompile(`^1[3-9]\d{9}$`)
	return phoneRegex.MatchString(phone)
}

// hashPassword 密码加密
func (uc *UserUsecase) hashPassword(password string) (string, error) {
	// 这里使用简单的MD5加密，实际应用中建议使用bcrypt
	hash := md5.Sum([]byte(password))
	return hex.EncodeToString(hash[:]), nil
}

// verifyPassword 验证密码
func (uc *UserUsecase) verifyPassword(hashedPassword, password string) bool {
	hash, err := uc.hashPassword(password)
	if err != nil {
		return false
	}
	return hash == hashedPassword
}
